BM算法

Pasted image 20250303010453.png

from pwn import *  
import numpy as np  
from tqdm import tqdm  
  
HOST = "bruh.chal.ctf.ae"  
r = remote(HOST, 443, ssl=True, sni=HOST)  
  
def get_sample_gata(guess):  
    r.sendlineafter(b"> (str)", guess)  
    r.recvuntil(b"RETURN = ")  
    sample_data = int(r.recvline().strip())  
    return sample_data  
  
# I know lfsr_flag ^ lfsr_guess = sample_data  
# send \x00 * 38 to get the output of only lfsr_flag  
  
# get sample_data  
guess = b'\x00' * 38  
sample_data = get_sample_gata(guess)  
print("Sample data: ", sample_data)  
sample_data = [int(i) for i in bin(sample_data)[2:].zfill(640)]  
  
  
def Berlekamp_Massey_algorithm(sequence):  
    N = len(sequence)  
    s = sequence[:]  
  
    for k in range(N):  
        if s[k] == 1:  
            break  
    f = set([k + 1, 0])  # use a set to denote polynomial  
    l = k + 1  
  
    g = set([0])  
    a = k  
    b = 0  
  
    for n in range(k + 1, N):  
        d = 0  
        for ele in f:  
            d ^= s[ele + n - l]  
  
        if d == 0:  
            b += 1  
        else:  
            if 2 * l > n:  
                f ^= set([a - b + ele for ele in g])  
                b += 1  
            else:  
                temp = f.copy()  
                f = set([b - a + ele for ele in f]) ^ g  
                l = n + 1 - l  
                g = temp  
                a = b  
                b = n - l + 1  
  
    # output the polynomial  
    def print_poly(polynomial):  
        result = ''  
        lis = sorted(polynomial, reverse=True)  
        for i in lis:  
            if i == 0:  
                result += '1'  
            else:  
                result += 'x^%s' % str(i)  
  
            if i != lis[-1]:  
                result += ' + '  
  
        return result  
  
    # return (print_poly(f), l)  
    # return the coefficients of the polynomial  
    f = [x - 1 for x in f if x != 0]  
    return list(f)  
  
taps = Berlekamp_Massey_algorithm(sample_data)  
print("Got taps:", taps)  
  
class LFSR:  
    def __init__(self, state: bytes, taps):  
        # self.state = [int(i) for i in '{:0{n}b}'.format(int.from_bytes(seed, 'big'), n=8*len(seed))]  
        self.taps = taps  
        self.state = state  
  
    def Run(self, k: int = 1):  
        out = []  
        for _ in range(k):  
            new = 0  
            for tap in self.taps:  
                new ^= self.state[tap]  
            out.append(self.state[-1])  
            self.state = [new] + self.state[:-1]  
        return out  
      
from z3 import *  
flag_state = [BitVec(f"state_{i}", 1) for i in range(38 * 8)]  
  
sample_data = sample_data[::-1]  
s = Solver()  
lfsr_flag = LFSR(flag_state, taps)  
print(len(sample_data))  
for i in range(2 ** 7 + 2 ** 9 - 1):  
    s.add(lfsr_flag.Run()[0] == int(sample_data[i]))  
  
def reverse_one_step(lfsr_state):  
    flag_state = [BitVec(f"state_{i}", 1) for i in range(38 * 8)]  
    lfsr_flag = LFSR(flag_state, taps)  
    lfsr_flag.Run(1)  
    s = Solver()  
    for i in range(38 * 8):  
        s.add(lfsr_flag.state[i] == lfsr_state[i])  
    if s.check() == sat:  
        m = s.model()  
        return [m[state].as_long() for state in flag_state]  
    return None  
  
  
while s.check() == sat:  
    model = s.model()  
    lfsr_state = [model[state].as_long() for state in flag_state]  
    # now reverse 1337 steps to get the flag  
    lfsr = LFSR(lfsr_state, taps)  
    for i in tqdm(range(1337)):  
        lfsr.state = reverse_one_step(lfsr.state)  
    flag = bytes([int(''.join(map(str, lfsr.state[i:i+8])), 2) for i in range(0, 38 * 8, 8)])  
    print(flag)  
    exit()
 

用BM算法求解lfsr的反馈多项式是极好的